package com.xyht.sca_s.student_manage_system.modules.asset.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xyht.sca_s.student_manage_system.common.commonReturn.CommonCodeEnum;
import com.xyht.sca_s.student_manage_system.common.commonReturn.CommonResult;
import com.xyht.sca_s.student_manage_system.common.commonReturn.ExceptionCast;
import com.xyht.sca_s.student_manage_system.common.commonReturn.ResponseResult;
import com.xyht.sca_s.student_manage_system.common.util.ApiModelUtil;
import com.xyht.sca_s.student_manage_system.common.util.CacheUtil;
import com.xyht.sca_s.student_manage_system.common.util.TimeUtil;
import com.xyht.sca_s.student_manage_system.modules.asset.entity.CategoryNode;
import com.xyht.sca_s.student_manage_system.modules.asset.entity.SmsAssetCategoryManagement;
import com.xyht.sca_s.student_manage_system.modules.asset.entity.SmsAssetFixedStorage;
import com.xyht.sca_s.student_manage_system.modules.asset.entity.req.SmsAssetFixedStorageBatchImportReq;
import com.xyht.sca_s.student_manage_system.modules.asset.entity.req.SmsAssetFixedStorageBatchReq;
import com.xyht.sca_s.student_manage_system.modules.asset.entity.req.SmsAssetFixedStorageExportReq;
import com.xyht.sca_s.student_manage_system.modules.asset.entity.req.SmsAssetFixedStorageReq;
import com.xyht.sca_s.student_manage_system.modules.asset.entity.resp.SmsAssetFixedStorageGroupResp;
import com.xyht.sca_s.student_manage_system.modules.asset.entity.resp.SmsAssetFixedStorageResp;
import com.xyht.sca_s.student_manage_system.modules.asset.entity.resp.SmsAssetUserResp;
import com.xyht.sca_s.student_manage_system.modules.asset.mapper.SmsAssetCategoryManagementMapper;
import com.xyht.sca_s.student_manage_system.modules.asset.mapper.SmsAssetFixedStorageMapper;
import com.xyht.sca_s.student_manage_system.modules.asset.service.SmsAssetFixedStorageService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xyht.sca_s.student_manage_system.modules.asset.util.AssetUtil;
import com.xyht.sca_s.student_manage_system.modules.asset.util.CategoryUtil;
import com.xyht.sca_s.student_manage_system.modules.common.entity.SmsImportTask;
import com.xyht.sca_s.student_manage_system.modules.common.entity.SmsImportTaskDetail;
import com.xyht.sca_s.student_manage_system.modules.common.mapper.SmsImportTaskDetailMapper;
import com.xyht.sca_s.student_manage_system.modules.common.mapper.SmsImportTaskMapper;
import com.xyht.sca_s.student_manage_system.modules.user.entity.SmsUser;
import com.xyht.sca_s.student_manage_system.modules.user.mapper.SmsUserMapper;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

import static com.xyht.sca_s.student_manage_system.common.util.ParamCheckUtil.isNullOrEmpty;
import static com.xyht.sca_s.student_manage_system.modules.asset.constant.AssetStatusConstant.*;
import static com.xyht.sca_s.student_manage_system.modules.asset.constant.CommonConstant.PER_SHEET_NUM;
import static com.xyht.sca_s.student_manage_system.modules.asset.constant.InStorageMethodConstant.IN_STORAGE_METHOD_FIXED_IMPORT;
import static com.xyht.sca_s.student_manage_system.modules.asset.constant.InStorageMethodConstant.IN_STORAGE_METHOD_FIXED_SINGLE;
import static com.xyht.sca_s.student_manage_system.modules.common.constant.TaskDetailReason.*;
import static com.xyht.sca_s.student_manage_system.modules.common.constant.TaskNameExample.*;
import static com.xyht.sca_s.student_manage_system.modules.common.constant.TaskStatus.TASK_STATUS_DONE;
import static com.xyht.sca_s.student_manage_system.modules.common.constant.TaskStatus.TASK_STATUS_ERR;
import static com.xyht.sca_s.student_manage_system.modules.common.constant.TaskTypeConstant.*;

/**
 * <p>
 * 固定资产库存 服务实现类
 * </p>
 *
 * @author XYHT
 * @since 2023-05-14
 */
@Service
public class SmsAssetFixedStorageServiceImpl extends ServiceImpl<SmsAssetFixedStorageMapper, SmsAssetFixedStorage> implements SmsAssetFixedStorageService {
    @Resource
    private SmsImportTaskMapper smsImportTaskMapper;
    @Resource
    private SmsImportTaskDetailMapper smsImportTaskDetailMapper;
    @Resource
    private SmsAssetFixedStorageMapper smsAssetFixedStorageMapper;
    @Resource
    private AssetUtil assetUtil;
    @Resource
    private SmsAssetCategoryManagementMapper smsAssetCategoryManagementMapper;
    @Resource
    private CacheUtil cacheUtil;
    @Resource
    private CategoryUtil categoryUtil;
    @Resource
    private SmsUserMapper smsUserMapper;

    @Override
    @Async
    public Future<ResponseResult> batchAddFixedStorage(Map<String, Object> map, String user_id) {
        JSONObject jsonObject = JSONObject.parseObject(JSON.toJSONString(map));
        List<SmsAssetFixedStorageBatchReq> assetFixedStorageList = JSONObject.parseArray(JSON.toJSONString(jsonObject.get("list")), SmsAssetFixedStorageBatchReq.class);
        if (assetFixedStorageList == null || assetFixedStorageList.size() < 1) {
            return new AsyncResult<>(CommonResult.failed(CommonCodeEnum.INVALID_PARAM));
        }
        //创建导入任务
        SmsImportTask smsImportTask = new SmsImportTask();
        smsImportTask.setTaskName(TASK_NAME_ASSET_FIXED_IMPORT);
        smsImportTask.setUserId(user_id);
        smsImportTask.setTaskType(TASK_TYPE_ASSET_FIXED);
        smsImportTaskMapper.insert(smsImportTask);

        batchAddFixedStorage(assetFixedStorageList, smsImportTask.getId(), user_id);

        return new AsyncResult<>(CommonResult.success());
    }

    @Override
    @Transactional
    public ResponseResult singleAddFixedStorage(SmsAssetFixedStorageReq storageReq, String user_id) {
        if (isNullOrEmpty(storageReq.getAssetLifetime(), storageReq.getAssetResidualRate())) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        if (storageReq.getAssetResidualRate().compareTo(BigDecimal.ONE) > 0
        || storageReq.getAssetResidualRate().compareTo(BigDecimal.ZERO) < 0){
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }
        //校验残值比单价小
        BigDecimal assetResidualPrice = storageReq.getAssetPrice().multiply(storageReq.getAssetResidualRate());
        if (storageReq.getAssetPrice().compareTo(assetResidualPrice) < 0) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        SmsAssetCategoryManagement assetCategoryManagement =
                smsAssetCategoryManagementMapper.selectById(storageReq.getAssetCategory());
        if (assetCategoryManagement == null || isNullOrEmpty(assetCategoryManagement.getId())) {
            return CommonResult.failed(CommonCodeEnum.ASSET_CATEGORY_NOT_EXIST);
        }

        //判断是否为根类别
        if (assetCategoryManagement.getId().length() < 3) {
            return CommonResult.failed(CommonCodeEnum.ASSET_CATEGORY_CAN_NOT_USE_ROOT);
        }

        //判断数量
        if (storageReq.getAssetNum().equals(0)) {
            return CommonResult.failed(CommonCodeEnum.ASSET_STORAGE_NUM_ERR);
        }

//        //判断维保时长
//        if (storageReq.getAssetMaintenanceDuration().equals(0)) {
//            return CommonResult.failed(CommonCodeEnum.ASSET_STORAGE_MAINTENANCE_ERR);
//        }

        try {
            Date now_date = new Date();
            Date maintenance_expire_date = TimeUtil.AddMonths(now_date, storageReq.getAssetMaintenanceDuration());
            for (int i = 0; i < storageReq.getAssetNum(); i++) {
                String asset_id = assetUtil.createAssetStorageID(storageReq.getAssetCategory(),
                        now_date,
                        IN_STORAGE_METHOD_FIXED_SINGLE,
                        0);

                SmsAssetFixedStorage addAssetStorage = new SmsAssetFixedStorage();
                BeanUtils.copyProperties(storageReq, addAssetStorage);
                addAssetStorage.setAssetStatus(ASSET_STATUS_IN_STORAGE);
                addAssetStorage.setId(asset_id);
                addAssetStorage.setAddUserId(user_id);
                addAssetStorage.setAssetNum(1);
                addAssetStorage.setAssetMaintenanceExpire(maintenance_expire_date);

                //资产折旧
                addAssetStorage.setAssetLifetime(storageReq.getAssetLifetime());
                addAssetStorage.setAssetResidualPrice(assetResidualPrice);
                addAssetStorage.setAssetRealPrice(storageReq.getAssetPrice());
                addAssetStorage.setAssetTotalDepreciationPrice(new BigDecimal(0));
                addAssetStorage.setAssetBuyMonth(0);
                addAssetStorage.setAssetResidualRate(storageReq.getAssetResidualRate());

                //计算每月折旧和误差
                roundToTwoDecimals(addAssetStorage);

                smsAssetFixedStorageMapper.insert(addAssetStorage);
            }
        } catch (Exception e) {
            e.printStackTrace();
            ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.FAIL));
        }
        return CommonResult.success();
    }

    private void roundToTwoDecimals(SmsAssetFixedStorage addAssetStorage) {
        BigDecimal lifetimeResult = new BigDecimal(addAssetStorage.getAssetLifetime());
        //初始价格
        //总价-残值 = 总折旧价值（subResult）
        //月折旧（result） = 总折旧价值/资产寿命
        //根据误差计算出最后一个月折旧（lastMonth）
        //用月折旧数倒推月折旧率
        BigDecimal dividend = addAssetStorage.getAssetPrice();
        BigDecimal subResult = addAssetStorage.getAssetPrice().subtract(addAssetStorage.getAssetResidualPrice());
        BigDecimal result = divideAndRound(subResult,
                lifetimeResult,
                2);

        // 根据结果与除数计算回被除数
        BigDecimal approxDividend = result.multiply(lifetimeResult);

        // 计算误差
        BigDecimal error = subResult.subtract(approxDividend);
        BigDecimal lastMonth = result.add(error);

        addAssetStorage.setAssetPerDepreciationPrice(result);
        addAssetStorage.setAssetLastMonthDepreciationPrice(lastMonth);
        addAssetStorage.setAssetDepreciationRate(divideAndRound(result,addAssetStorage.getAssetPrice(),4));
        addAssetStorage.setAssetLastMonthDepreciationRate(divideAndRound(lastMonth,addAssetStorage.getAssetPrice(),4));
    }

    private BigDecimal divideAndRound(BigDecimal dividend, BigDecimal divisor, int scale) {
        return dividend.divide(divisor, scale, RoundingMode.HALF_UP);
    }

    @Override
    public ResponseResult getFixedStorage(String search_str, String asset_name, String asset_model,
                                          String asset_brand, String asset_category_id,
                                          Integer asset_status, String asset_id, BigDecimal asset_price,
                                          String asset_place,
                                          Integer pageNum, Integer pageSize) {
        Page<SmsAssetFixedStorage> page = new Page<>(pageNum, pageSize);
        QueryWrapper<SmsAssetFixedStorage> queryWrapper = new QueryWrapper<>();
        if (!isNullOrEmpty(asset_name)) {
            queryWrapper.lambda().like(SmsAssetFixedStorage::getAssetName, asset_name);
        }
        if (!isNullOrEmpty(asset_model)) {
            queryWrapper.lambda().like(SmsAssetFixedStorage::getAssetModel, asset_model);
        }
        if (!isNullOrEmpty(asset_brand)) {
            queryWrapper.lambda().like(SmsAssetFixedStorage::getAssetBrand, asset_brand);
        }
        if (!isNullOrEmpty(asset_category_id)) {
            queryWrapper.lambda().eq(SmsAssetFixedStorage::getAssetCategory, asset_category_id);
        }
        if (!isNullOrEmpty(asset_id)) {
            queryWrapper.lambda().eq(SmsAssetFixedStorage::getId, asset_id);
        }
        if (!isNullOrEmpty(asset_price)) {
            queryWrapper.lambda().eq(SmsAssetFixedStorage::getId, asset_price);
        }
        if (!isNullOrEmpty(asset_place)) {
            queryWrapper.lambda().eq(SmsAssetFixedStorage::getAssetPlace, asset_place);
        }

        if (!isNullOrEmpty(search_str)) {
            queryWrapper.lambda().and(lambdaQuery ->
                    lambdaQuery.like(SmsAssetFixedStorage::getAssetName, search_str)
                            .or()
                            .like(SmsAssetFixedStorage::getAssetModel, search_str)
                            .or()
                            .like(SmsAssetFixedStorage::getAssetBrand, search_str)
                            .or()
                            .like(SmsAssetFixedStorage::getAssetPrice, search_str)
                            .or()
                            .like(SmsAssetFixedStorage::getId, search_str)
                            .or()
                            .like(SmsAssetFixedStorage::getAssetPlace, search_str)
            );
        }
        if (!isNullOrEmpty(asset_status)) {
            queryWrapper.lambda().eq(SmsAssetFixedStorage::getAssetStatus, asset_status)
                    .orderByAsc(SmsAssetFixedStorage::getAssetStatus);
        }
        queryWrapper.lambda()
                .orderByDesc(SmsAssetFixedStorage::getCreateTime);

        smsAssetFixedStorageMapper.selectPage(page, queryWrapper);
        List<SmsAssetFixedStorageResp> list = page.getRecords()
                .stream()
                .map(storage -> {
                    SmsAssetFixedStorageResp smsAssetFixedStorageResp = new SmsAssetFixedStorageResp();
                    BeanUtils.copyProperties(storage, smsAssetFixedStorageResp);

                    SmsAssetCategoryManagement categoryManagement =
                            smsAssetCategoryManagementMapper.selectById(storage.getAssetCategory());
                    if (categoryManagement != null) {
                        smsAssetFixedStorageResp.setAssetCategoryName(categoryManagement.getCategoryName());
                    }

                    SmsUser smsUser = cacheUtil.getUserInfo(storage.getAddUserId());
                    if (smsUser != null) {
                        SmsAssetUserResp smsAssetUserResp = new SmsAssetUserResp();
                        BeanUtils.copyProperties(smsUser, smsAssetUserResp);
                        smsAssetFixedStorageResp.setUserInfo(smsAssetUserResp);
                    }
                    SmsUser ownerUser = cacheUtil.getUserInfo(storage.getAssetOwner());
                    if (ownerUser != null) {
                        SmsAssetUserResp smsAssetUserResp = new SmsAssetUserResp();
                        BeanUtils.copyProperties(ownerUser, smsAssetUserResp);
                        smsAssetFixedStorageResp.setOwnerUserInfo(smsAssetUserResp);
                    }

                    return smsAssetFixedStorageResp;
                })
                .collect(Collectors.toList());
        int total = (int) page.getTotal();
        return CommonResult.success(list, total);
    }

    @Resource
    PlatformTransactionManager transactionManager;

    private void batchAddFixedStorage(List<SmsAssetFixedStorageBatchReq> list, String task_id, String user_id) {
        int OFFSET_ROW = 3;
        Date now_date = new Date();
        Integer task_finish_status = TASK_STATUS_DONE;

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        String date_str = simpleDateFormat.format(now_date);

        Integer count = smsImportTaskMapper.selectCount(new QueryWrapper<SmsImportTask>()
                .lambda()
                .like(SmsImportTask::getCreateTime, date_str));

        for (int i = 0; i < list.size(); i++) {

            //开启事务
            DefaultTransactionDefinition dt = new DefaultTransactionDefinition();
            // 嵌套事务 PROPAGATION_REQUIRES_NEW 每次开启一个新的事务
            dt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
            // 设置嵌套事务
            TransactionStatus status = transactionManager.getTransaction(dt);

            try {
                SmsAssetFixedStorageBatchReq storage = list.get(i);
                if (isNullOrEmpty(storage.getAssetCategoryName())
                        || isNullOrEmpty(storage.getAssetName())
                        || isNullOrEmpty(storage.getAssetPrice())
                || isNullOrEmpty(storage.getAssetLifetime())
                || isNullOrEmpty(storage.getAssetResidualRate())) {
                    transactionManager.rollback(status);
                    task_finish_status = TASK_STATUS_ERR;
                    createTeacherImportTaskDetail(task_id, REASON_INVALID_PARAM, (i + OFFSET_ROW) + "");
                    continue;
                }

                if (storage.getAssetResidualRate().compareTo(BigDecimal.ONE) > 0
                        || storage.getAssetResidualRate().compareTo(BigDecimal.ZERO) < 0){
                    transactionManager.rollback(status);
                    task_finish_status = TASK_STATUS_ERR;
                    createTeacherImportTaskDetail(task_id, REASON_RESIDUAL_ERROR, (i + OFFSET_ROW) + "");
                    continue;
                }
                //校验残值比单价小
                BigDecimal assetResidualPrice = storage.getAssetPrice().multiply(storage.getAssetResidualRate());
                if (storage.getAssetPrice().compareTo(assetResidualPrice) < 0) {
                    transactionManager.rollback(status);
                    task_finish_status = TASK_STATUS_ERR;
                    createTeacherImportTaskDetail(task_id, REASON_RESIDUAL_ERROR, (i + OFFSET_ROW) + "");
                    continue;
                }

                SmsAssetCategoryManagement categoryManagement =
                        smsAssetCategoryManagementMapper.selectOne(new QueryWrapper<SmsAssetCategoryManagement>()
                                .lambda()
                                .eq(SmsAssetCategoryManagement::getCategoryName, storage.getAssetCategoryName()));
                if (categoryManagement == null || isNullOrEmpty(categoryManagement.getId())) {
                    transactionManager.rollback(status);
                    task_finish_status = TASK_STATUS_ERR;
                    createTeacherImportTaskDetail(task_id, REASON_ASSET_CATEGORY_NOT_EXIST, (i + OFFSET_ROW) + "");
                    continue;
                }
                //判断是否为根类别
                if (categoryManagement.getId().length() < 3) {
                    transactionManager.rollback(status);
                    task_finish_status = TASK_STATUS_ERR;
                    createTeacherImportTaskDetail(task_id, REASON_ASSET_CATEGORY_CAN_NOT_USE_ROOT, (i + OFFSET_ROW) + "");
                    continue;
                }

                //判断数量
                if (isNullOrEmpty(storage.getAssetNum()) || storage.getAssetNum().equals(0)) {
//                transactionManager.rollback(status);
//                task_finish_status = TASK_STATUS_ERR;
//                createTeacherImportTaskDetail(task_id, REASON_ASSET_NUM_ERR, (i + OFFSET_ROW) + "");
                    continue;
                }

                //判断维保时长
//            if (storage.getAssetMaintenanceDuration().equals(0)) {
//                transactionManager.rollback(status);
//                task_finish_status = TASK_STATUS_ERR;
//                createTeacherImportTaskDetail(task_id, REASON_ASSET_MAINTENANCE_ERR, (i + OFFSET_ROW) + "");
//                continue;
//            }


                Date maintenance_expire_date;
                if (!isNullOrEmpty(storage.getAssetMaintenanceDuration())) {
                    maintenance_expire_date = TimeUtil.AddMonths(now_date, storage.getAssetMaintenanceDuration());
                } else {
                    maintenance_expire_date = TimeUtil.AddMonths(now_date, 36);
                }
                for (int j = 0; j < storage.getAssetNum(); j++) {
                    String asset_id = assetUtil.createAssetStorageID(categoryManagement.getId(),
                            now_date,
                            IN_STORAGE_METHOD_FIXED_IMPORT,
                            count + 1,
                            i + 1,
                            j + 1);

                    SmsAssetFixedStorage addAssetStorage = new SmsAssetFixedStorage();
                    BeanUtils.copyProperties(storage, addAssetStorage);

                    addAssetStorage.setAssetModel(isNullOrEmpty(storage.getAssetModel()) ? "无" : storage.getAssetModel());
                    addAssetStorage.setAssetBrand(isNullOrEmpty(storage.getAssetBrand()) ? "无" : storage.getAssetBrand());

                    addAssetStorage.setAssetCategory(categoryManagement.getId());
                    addAssetStorage.setAssetStatus(ASSET_STATUS_IN_STORAGE);
                    addAssetStorage.setId(asset_id);
                    addAssetStorage.setAddUserId(user_id);
                    addAssetStorage.setAssetNum(1);
                    addAssetStorage.setAssetMaintenanceExpire(maintenance_expire_date);

                    //资产折旧
                    addAssetStorage.setAssetLifetime(storage.getAssetLifetime());
                    addAssetStorage.setAssetResidualPrice(storage.getAssetResidualPrice());
                    addAssetStorage.setAssetRealPrice(storage.getAssetPrice());
                    addAssetStorage.setAssetTotalDepreciationPrice(new BigDecimal(0));
                    addAssetStorage.setAssetBuyMonth(0);
                    addAssetStorage.setAssetResidualRate(storage.getAssetResidualRate());

                    //计算每月折旧和误差
                    roundToTwoDecimals(addAssetStorage);

                    smsAssetFixedStorageMapper.insert(addAssetStorage);
                }

                transactionManager.commit(status);
            } catch (Exception e) {
                e.printStackTrace();
                transactionManager.rollback(status);
                task_finish_status = TASK_STATUS_ERR;
                createTeacherImportTaskDetail(task_id, REASON_IMPORT_ERR, (i + OFFSET_ROW) + "");
            } finally {
                if (status.isNewTransaction() && !status.isCompleted()) {
                    transactionManager.commit(status);
                    log.debug("++++++进来了");
                }
            }
        }
        SmsImportTask smsImportTask = new SmsImportTask();
        smsImportTask.setId(task_id);
        smsImportTask.setStatus(task_finish_status);
        smsImportTaskMapper.updateById(smsImportTask);
    }

    private void createTeacherImportTaskDetail(String task_id, String reason, String row) {
        SmsImportTaskDetail smsImportTaskDetail = new SmsImportTaskDetail();
        smsImportTaskDetail.setTaskId(task_id);
        smsImportTaskDetail.setFailReason(reason);
//        smsImportTaskDetail.setFailName(name);
        smsImportTaskDetail.setFailRow(row);
        smsImportTaskDetailMapper.insert(smsImportTaskDetail);
    }

    @Override
    public ResponseResult getExistAssetFixedStorageGroup(String search_str, String asset_category_id, Integer pageNum, Integer pageSize) {
        Page<SmsAssetFixedStorage> page = new Page<>(pageNum, pageSize);
        QueryWrapper<SmsAssetFixedStorage> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().ne(SmsAssetFixedStorage::getAssetStatus, ASSET_STATUS_OUT);

        if (!isNullOrEmpty(asset_category_id) && !asset_category_id.equals("0")) {
            SmsAssetCategoryManagement originCategory = smsAssetCategoryManagementMapper.selectById(asset_category_id);
            if (originCategory == null) {
                return CommonResult.failed(CommonCodeEnum.ASSET_CATEGORY_NOT_EXIST);
            }
            CategoryNode originCategoryNode = new CategoryNode();
            BeanUtils.copyProperties(originCategory, originCategoryNode);

            List<CategoryNode> categoryList =
                    smsAssetCategoryManagementMapper.selectList(new QueryWrapper<>())
                            .stream()
                            .map(category -> {
                                CategoryNode categoryNode = new CategoryNode();
                                BeanUtils.copyProperties(category, categoryNode);
                                return categoryNode;
                            })
                            .collect(Collectors.toList());

            CategoryNode resultCategory = categoryUtil.getChildrenNode(originCategoryNode, categoryList);
            List<String> childrenList = new ArrayList<>();
            childrenList = categoryUtil.getChildrenIDList(resultCategory, childrenList);
            childrenList.add(resultCategory.getId());
            queryWrapper.lambda().in(SmsAssetFixedStorage::getAssetCategory, childrenList);
        }
        if (!isNullOrEmpty(search_str)) {
            queryWrapper.lambda().and(lambdaQuery ->
                    lambdaQuery.like(SmsAssetFixedStorage::getAssetName, search_str)
                            .or()
                            .like(SmsAssetFixedStorage::getAssetModel, search_str)
                            .or()
                            .like(SmsAssetFixedStorage::getAssetBrand, search_str)
                            .or()
                            .like(SmsAssetFixedStorage::getAssetPrice, search_str)
            );
        }

        queryWrapper.select("asset_name, asset_model, asset_brand,asset_price,asset_category,count(asset_num) as asset_num,sum(asset_price) as total_price")
                .lambda().groupBy(SmsAssetFixedStorage::getAssetName)
                .groupBy(SmsAssetFixedStorage::getAssetModel)
                .groupBy(SmsAssetFixedStorage::getAssetBrand)
                .groupBy(SmsAssetFixedStorage::getAssetPrice)
                .groupBy(SmsAssetFixedStorage::getAssetCategory)
        ;
        smsAssetFixedStorageMapper.selectPage(page, queryWrapper);

        List<SmsAssetFixedStorageGroupResp> respList = page.getRecords()
                .stream()
                .map(storage -> {
                    SmsAssetFixedStorageGroupResp storageResp = new SmsAssetFixedStorageGroupResp();
                    BeanUtils.copyProperties(storage, storageResp);

                    SmsAssetCategoryManagement categoryManagement =
                            smsAssetCategoryManagementMapper.selectById(storage.getAssetCategory());

                    if (categoryManagement != null) {
                        storageResp.setAssetCategoryName(categoryManagement.getCategoryName());
                        storageResp.setAssetCategoryId(categoryManagement.getId());
                    }
                    return storageResp;
                })
                .collect(Collectors.toList());
        int total = (int) page.getTotal();
        return CommonResult.success(respList, total);
    }

    @Resource
    private ApiModelUtil apiModelUtil;

    @Override
    public Future<ResponseResult> exportAssetFixedStorage(SmsAssetFixedStorageExportReq storageExportReq, HttpServletResponse response) {
        try {
            QueryWrapper<SmsAssetFixedStorage> queryWrapper = new QueryWrapper<>();
            if (!isNullOrEmpty(storageExportReq.getAssetName())) {
                queryWrapper.lambda().like(SmsAssetFixedStorage::getAssetName, storageExportReq.getAssetName());
            }
            if (!isNullOrEmpty(storageExportReq.getAssetModel())) {
                queryWrapper.lambda().like(SmsAssetFixedStorage::getAssetModel, storageExportReq.getAssetModel());
            }
            if (!isNullOrEmpty(storageExportReq.getAssetBrand())) {
                queryWrapper.lambda().like(SmsAssetFixedStorage::getAssetBrand, storageExportReq.getAssetBrand());
            }
            if (!isNullOrEmpty(storageExportReq.getAssetCategory())) {
                queryWrapper.lambda().eq(SmsAssetFixedStorage::getAssetCategory, storageExportReq.getAssetCategory());
            }
            if (!isNullOrEmpty(storageExportReq.getId())) {
                queryWrapper.lambda().eq(SmsAssetFixedStorage::getId, storageExportReq.getId());
            }
            if (!isNullOrEmpty(storageExportReq.getAssetPrice())) {
                queryWrapper.lambda().eq(SmsAssetFixedStorage::getId, storageExportReq.getAssetPrice());
            }
            if (!isNullOrEmpty(storageExportReq.getAssetPlace())) {
                queryWrapper.lambda().eq(SmsAssetFixedStorage::getAssetPlace, storageExportReq.getAssetPlace());
            }

            if (!isNullOrEmpty(storageExportReq.getSearchStr())) {
                queryWrapper.lambda().and(lambdaQuery ->
                        lambdaQuery.like(SmsAssetFixedStorage::getAssetName, storageExportReq.getSearchStr())
                                .or()
                                .like(SmsAssetFixedStorage::getAssetModel, storageExportReq.getSearchStr())
                                .or()
                                .like(SmsAssetFixedStorage::getAssetBrand, storageExportReq.getSearchStr())
                                .or()
                                .like(SmsAssetFixedStorage::getAssetPrice, storageExportReq.getSearchStr())
                                .or()
                                .like(SmsAssetFixedStorage::getId, storageExportReq.getSearchStr())
                                .or()
                                .like(SmsAssetFixedStorage::getAssetPlace, storageExportReq.getSearchStr())
                );
            }
            if (!isNullOrEmpty(storageExportReq.getAssetStatus())) {
                queryWrapper.lambda().eq(SmsAssetFixedStorage::getAssetStatus, storageExportReq.getAssetStatus())
                        .orderByAsc(SmsAssetFixedStorage::getAssetStatus);
            }
            queryWrapper.lambda()
                    .orderByDesc(SmsAssetFixedStorage::getCreateTime);
            List<SmsAssetFixedStorage> list = smsAssetFixedStorageMapper.selectList(queryWrapper);
            //表头数据
            String[] header = storageExportReq.getLimitColumn().toArray(new String[0]);
            double sheetNum;
            //声明一个工作簿
            HSSFWorkbook workbook = new HSSFWorkbook();
            if (list != null && list.size() > 0) {
                sheetNum = Math.ceil((double) list.size() / PER_SHEET_NUM);
                for (int k = 0; k < sheetNum; k++) {
                    //生成一个表格，设置表格名称为"资源导出表"
                    HSSFSheet sheet = workbook.createSheet("资产导出表" + (k + 1));

                    //设置表格列宽度为10个字节
                    sheet.setDefaultColumnWidth(12);
                    //创建标题的显示样式
                    HSSFCellStyle headerStyle = workbook.createCellStyle();
                    headerStyle.setFillForegroundColor(IndexedColors.YELLOW.index);
                    headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);

                    HSSFFont f = workbook.createFont();
                    f.setFontHeightInPoints((short) 10);//字号
                    f.setBold(true);//加粗
                    headerStyle.setFont(f);
                    //创建第一行表头
                    HSSFRow headrow = sheet.createRow(0);

                    //遍历添加表头
                    for (int i = 0; i < header.length + 1; i++) {
                        //创建一个单元格
                        HSSFCell cell = headrow.createCell(i);

                        if (i == 0) {
                            //创建一个内容对象
                            HSSFRichTextString text = new HSSFRichTextString("序号");
                            //将内容对象的文字内容写入到单元格中
                            cell.setCellValue(text);
                            cell.setCellStyle(headerStyle);
                            continue;
                        }
                        //创建一个内容对象
                        String header1 = apiModelUtil.getFieldValueByFieldName(SmsAssetFixedStorage.class, header[i - 1]);
                        HSSFRichTextString text = new HSSFRichTextString(header1);

                        //将内容对象的文字内容写入到单元格中
                        cell.setCellValue(text);
                        cell.setCellStyle(headerStyle);
                    }

                    int range = PER_SHEET_NUM;
                    if (k + 1 == sheetNum) {
                        range = list.size() - (PER_SHEET_NUM) * k;
                    }
                    for (int i = 0; i < range; i++) {
                        //创建一行
                        HSSFRow row1 = sheet.createRow(i + 1);
                        SmsAssetFixedStorage studentInfo = list.get((PER_SHEET_NUM) * k + i);
                        Map<String, Object> map = JSONObject.parseObject(JSON.toJSONString(studentInfo), Map.class);
                        row1.createCell(0).setCellValue(new HSSFRichTextString(i + 1 + ""));
                        for (int j = 0; j < header.length; j++) {
                            String rowContent = "";
                            if (map.get(header[j]) instanceof Integer) {
                                Integer value = (Integer) map.get(header[j]);
                                if (value == null) {
                                    rowContent = "";
                                } else if (header[j].equals("assetStatus")) {
                                    if (value.equals(ASSET_STATUS_FREE)) {
                                        rowContent = "闲置(可借用)";

                                    } else if (value.equals(ASSET_STATUS_IN_STORAGE)) {
                                        rowContent = "空闲（库中）";
                                    } else if (value.equals(ASSET_STATUS_BORROW)) {
                                        rowContent = "借用中";
                                    } else if (value.equals(ASSET_STATUS_REPAIR)) {
                                        rowContent = "维修中";
                                    } else {
                                        rowContent = "已处置";
                                    }
                                }
                                row1.createCell(j + 1).setCellValue(new HSSFRichTextString(rowContent));
                                continue;
                            }

                            if (map.get(header[j]) instanceof String) {
                                String value = (String) map.get(header[j]);
                                if (value == null) {
                                    rowContent = "";
                                } else if (header[j].equals("assetOwner")) {
                                    SmsUser smsUser = smsUserMapper.selectById(value);
                                    if (smsUser != null) {
                                        rowContent = smsUser.getRealName();
                                    } else {
                                        rowContent = "";
                                    }
                                } else {
                                    rowContent = value;
                                }
                                row1.createCell(j + 1).setCellValue(new HSSFRichTextString(rowContent));
                                continue;
                            }


                            if (map.get(header[j]) instanceof Long) {
                                rowContent = TimeUtil.DateHanZiSimpleTimestamp((long) map.get(header[j]));
                            } else {
                                rowContent = (String) map.get(header[j]);
                            }
                            row1.createCell(j + 1).setCellValue(new HSSFRichTextString(rowContent));
                        }
                    }
                }
            }

            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("导出表.xlsx", "utf-8"));
            response.setCharacterEncoding("utf-8");
            response.setHeader("file-type", "download");
            response.setHeader("file-name", URLEncoder.encode("资产导出表.xlsx", "utf-8"));
            response.setHeader("Access-Control-Expose-Headers", "file-type,file-name");
//            //刷新缓冲
            response.flushBuffer();
            //workbook将Excel写入到response的输出流中，供页面下载
            OutputStream os = response.getOutputStream();
            workbook.write(os);

            workbook.close();
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
            return new AsyncResult<>(CommonResult.failed(CommonCodeEnum.FAIL));
        }
        return new AsyncResult<>(CommonResult.success());
    }

    @Override
    public Future<ResponseResult> batchUpdateFixedStorage(SmsAssetFixedStorageBatchImportReq batchImportReq, String user_id) {
        if (batchImportReq.getAssetList() == null || batchImportReq.getAssetList().size() < 1) {
            return new AsyncResult<>(CommonResult.failed(CommonCodeEnum.INVALID_PARAM));
        }
        //创建导入任务
        SmsImportTask smsImportTask = new SmsImportTask();
        smsImportTask.setTaskName(TASK_NAME_ASSET_FIXED_UPDATE_IMPORT);
        smsImportTask.setUserId(user_id);
        smsImportTask.setTaskType(TASK_TYPE_ASSET_FIXED_UPDATE);
        smsImportTaskMapper.insert(smsImportTask);

        batchUpdateFixedStorage(batchImportReq.getAssetList(), smsImportTask.getId(), user_id);
        return new AsyncResult<>(CommonResult.success());
    }

    @Override
    public ResponseResult updateFixedStorage(SmsAssetFixedStorageReq storageReq) {
        if (isNullOrEmpty(storageReq.getId(), storageReq.getAssetCategory())) {
            return CommonResult.failed(CommonCodeEnum.INVALID_PARAM);
        }

        SmsAssetCategoryManagement assetCategoryManagement =
                smsAssetCategoryManagementMapper.selectById(storageReq.getAssetCategory());
        if (assetCategoryManagement == null || isNullOrEmpty(assetCategoryManagement.getId())) {
            return CommonResult.failed(CommonCodeEnum.ASSET_CATEGORY_NOT_EXIST);
        }

        //判断是否为根类别
        if (assetCategoryManagement.getId().length() < 3) {
            return CommonResult.failed(CommonCodeEnum.ASSET_CATEGORY_CAN_NOT_USE_ROOT);
        }

        SmsAssetFixedStorage updateAssetStorage = new SmsAssetFixedStorage();
        BeanUtils.copyProperties(storageReq, updateAssetStorage);

        smsAssetFixedStorageMapper.updateById(updateAssetStorage);
        return CommonResult.success();
    }

    private void batchUpdateFixedStorage(List<SmsAssetFixedStorageBatchReq> list, String task_id, String user_id) {
        int OFFSET_ROW = 3;
        int task_finish_status = TASK_STATUS_DONE;

        for (int i = 0; i < list.size(); i++) {

            //开启事务
            DefaultTransactionDefinition dt = new DefaultTransactionDefinition();
            // 嵌套事务 PROPAGATION_REQUIRES_NEW 每次开启一个新的事务
            dt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
            // 设置嵌套事务
            TransactionStatus status = transactionManager.getTransaction(dt);

            try {
                SmsAssetFixedStorageBatchReq storage = list.get(i);
                if (isNullOrEmpty(storage.getId(), storage.getAssetCategoryName())) {
                    transactionManager.rollback(status);
                    task_finish_status = TASK_STATUS_ERR;
                    createTeacherImportTaskDetail(task_id, REASON_INVALID_PARAM, (i + OFFSET_ROW) + "");
                    continue;
                }

                //校验资产id
                SmsAssetFixedStorage fixedStorage = smsAssetFixedStorageMapper.selectById(storage.getId());
                if (fixedStorage == null) {
                    transactionManager.rollback(status);
                    task_finish_status = TASK_STATUS_ERR;
                    createTeacherImportTaskDetail(task_id, REASON_ASSET_STORAGE_NOT_EXIST, (i + OFFSET_ROW) + "");
                    continue;
                }

                SmsAssetCategoryManagement categoryManagement =
                        smsAssetCategoryManagementMapper.selectOne(new QueryWrapper<SmsAssetCategoryManagement>()
                                .lambda()
                                .eq(SmsAssetCategoryManagement::getCategoryName, storage.getAssetCategoryName()));
                if (categoryManagement == null || isNullOrEmpty(categoryManagement.getId())) {
                    transactionManager.rollback(status);
                    task_finish_status = TASK_STATUS_ERR;
                    createTeacherImportTaskDetail(task_id, REASON_ASSET_CATEGORY_NOT_EXIST, (i + OFFSET_ROW) + "");
                    continue;
                }
                //判断是否为根类别
                if (categoryManagement.getId().length() < 3) {
                    transactionManager.rollback(status);
                    task_finish_status = TASK_STATUS_ERR;
                    createTeacherImportTaskDetail(task_id, REASON_ASSET_CATEGORY_CAN_NOT_USE_ROOT, (i + OFFSET_ROW) + "");
                    continue;
                }

                for (int j = 0; j < storage.getAssetNum(); j++) {

                    SmsAssetFixedStorage updateAssetStorage = new SmsAssetFixedStorage();

                    updateAssetStorage.setAssetModel(isNullOrEmpty(storage.getAssetModel()) ? "无" : storage.getAssetModel());
                    updateAssetStorage.setAssetBrand(isNullOrEmpty(storage.getAssetBrand()) ? "无" : storage.getAssetBrand());
                    updateAssetStorage.setAssetName(isNullOrEmpty(storage.getAssetName()) ? "无" : storage.getAssetName());
                    updateAssetStorage.setAssetPlace(isNullOrEmpty(storage.getAssetPlace()) ? "无" : storage.getAssetPlace());

                    updateAssetStorage.setAssetCategory(categoryManagement.getId());
                    updateAssetStorage.setId(storage.getId());
                    updateAssetStorage.setAddUserId(user_id);
//                    updateAssetStorage.setAssetNum(1);

                    smsAssetFixedStorageMapper.updateById(updateAssetStorage);
                }

                transactionManager.commit(status);
            } catch (Exception e) {
                e.printStackTrace();
                transactionManager.rollback(status);
                task_finish_status = TASK_STATUS_ERR;
                createTeacherImportTaskDetail(task_id, REASON_IMPORT_ERR, (i + OFFSET_ROW) + "");
            } finally {
                if (status.isNewTransaction() && !status.isCompleted()) {
                    transactionManager.commit(status);
                    log.debug("++++++进来了");
                }
            }
        }
        SmsImportTask smsImportTask = new SmsImportTask();
        smsImportTask.setId(task_id);
        smsImportTask.setStatus(task_finish_status);
        smsImportTaskMapper.updateById(smsImportTask);
    }

}
